enum EnumSequence {
  start = 'start',
  stop = 'stop',
  alarm = 'alarm',
  engineBoom = 'engineBoom'
}

abstract class CarModel {

  sequenceLists: Set<EnumSequence> = new Set()

  protected start(): void { }
  protected stop(): void { }
  protected alarm(): void { }
  protected engineBoom(): void { }

  public run() {
    this.sequenceLists.forEach((v) => {
      try {
        this[EnumSequence[v]]()
      } catch (error) {
        console.error(error);
      }
    })
  }

  public setSequence(sequence: EnumSequence) {
    this.sequenceLists.add(sequence)
  }
}

class BenzModel extends CarModel {
  protected start() {
    console.log('奔驰启动');
  }
  protected stop() {
    console.log('奔驰停车');
  }
  protected alarm() {
    console.log('奔驰鸣笛');
  }
  protected engineBoom() {
    console.log('奔驰引擎');
  }
}

class BMWModel extends CarModel {
  protected start() {
    console.log('宝马启动');
  }
  protected stop() {
    console.log('宝马停车');
  }
  protected alarm() {
    console.log('宝马鸣笛');
  }
  protected engineBoom() {
    console.log('宝马引擎');
  }
}

abstract class CarBuilder {
  abstract getCarModel(): CarModel
}

class BenzBuilder extends CarBuilder {
  private benz = new BenzModel()

  setSequence(sequence: EnumSequence): void {
    this.benz.setSequence(sequence)
  }

  getCarModel() {
    return this.benz
  }
}

class BMWBuilder extends CarBuilder {
  private bmw = new BMWModel()

  setSequence(sequence: EnumSequence): void {
    this.bmw.setSequence(sequence)
  }

  getCarModel() {
    return this.bmw
  }
}

class Director {
  getABenzModel() {
    const benzBuilder = new BenzBuilder()
    benzBuilder.setSequence(EnumSequence.start)
    benzBuilder.setSequence(EnumSequence.engineBoom)
    benzBuilder.setSequence(EnumSequence.stop)
    return benzBuilder.getCarModel()
  }
  getBBenzModel() {
    const benzBuilder = new BenzBuilder()
    benzBuilder.setSequence(EnumSequence.stop)
    benzBuilder.setSequence(EnumSequence.engineBoom)
    benzBuilder.setSequence(EnumSequence.start)
    return benzBuilder.getCarModel()
  }

  getCBMWModel() {
    const bmwBuilder = new BMWBuilder()
    bmwBuilder.setSequence(EnumSequence.start)
    return bmwBuilder.getCarModel()
  }

  getDBMWModel() {
    const bmwBuilder = new BMWBuilder()
    bmwBuilder.setSequence(EnumSequence.engineBoom)
    return bmwBuilder.getCarModel()
  }
}

const director = new Director()
director.getABenzModel().run()
console.log('-------------');
director.getBBenzModel().run()
console.log('-------------');
director.getCBMWModel().run()
console.log('-------------');
director.getDBMWModel().run()

// const benz = new BenzBuilder()
// benz.setSequence(EnumSequence.start)
// benz.setSequence(EnumSequence.engineBoom)
// benz.setSequence(EnumSequence.stop)
// benz.getCarModel().run()
// console.log('----------------');
// const bmw = new BMWBuilder()
// bmw.setSequence(EnumSequence.engineBoom)
// bmw.setSequence(EnumSequence.start)
// bmw.setSequence(EnumSequence.stop)
// bmw.getCarModel().run()


// const benz = new BenzModel()
// benz.setSequence(EnumSequence.start)
// benz.setSequence(EnumSequence.engineBoom)
// benz.setSequence(EnumSequence.stop)

// benz.run()